package com.webservice.service;

import com.pangus.common.dto.ApiResponse;
import com.webservice.dto.ResponseCommonForm;
import com.webservice.dto.Table;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

public class RmGetDataApiService {

    public List<ResponseCommonForm> xmlGetDate(String docType, String xml) throws IOException, DocumentException {
        LocalDateTime localDateTimeStart = LocalDateTime.now();
        System.out.println("开始时间: "+ localDateTimeStart);

        //发送请求
        CloseableHttpResponse response = accessService(docType, xmlToPost(xml));

        //解析请求返回结果
        List<ResponseCommonForm> responseCommonForms = resultAnalysis(response);

        LocalDateTime localDateTimeEnd = LocalDateTime.now();
        System.out.println("结束时间: "+ localDateTimeEnd);
        Duration duration = Duration.between(localDateTimeStart, localDateTimeEnd);
        System.out.println("耗时: "+duration.toMillis() + "ms");

        return responseCommonForms;
    }

    public List<ResponseCommonForm> getDate(String docType, Map<String,String> map) throws IOException, DocumentException {
        LocalDateTime localDateTimeStart = LocalDateTime.now();
        System.out.println("开始时间: "+ localDateTimeStart);

        //请求条件
        String requsetData = toBase64Entity(map);

        //发送请求
        CloseableHttpResponse response = accessService(docType, requsetData);

        //解析请求返回结果
        List<ResponseCommonForm> responseCommonForms = resultAnalysis(response);

        LocalDateTime localDateTimeEnd = LocalDateTime.now();
        System.out.println("结束时间: "+ localDateTimeEnd);
        Duration duration = Duration.between(localDateTimeStart, localDateTimeEnd);
        System.out.println("耗时: "+duration.toMillis() + "ms");

        return responseCommonForms;
    }

    //对返回结果进行分析
    private List<ResponseCommonForm> resultAnalysis(CloseableHttpResponse response) throws DocumentException, IOException {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200){
            System.out.println("StatusCode : " + statusCode + "  请求成功");
        }else{
            System.out.println("StatusCode : " + statusCode + "  请求失败");
            return  null;
        }
        String responseEntity = EntityUtils.toString(response.getEntity(),"UTF-8");

//        responseEntity = stripNonValidXMLCharacters(responseEntity);
        //返回xmlstr结果进行分割
        Document document = DocumentHelper.parseText(responseEntity);
        Element root = document.getRootElement();
        Element return_code = root.element("X_RETURN_CODE");
        Element return_mesg = root.element("X_RETURN_MESG");
        if (return_code.getStringValue().equals("S1001000")){
            System.out.println("状态码: S1001000 发送接收成功");
        }else{
            System.out.println("状态码: " + return_code.getStringValue() + " 发送接收失败\n返回信息:" + return_mesg.getStringValue());
        }
        Element node=root.element("X_RESPONSE_DATA");
        System.out.println("返回信息为: "+return_mesg.getStringValue());
//        System.out.println(node.getStringValue());
        responseEntity = node.getStringValue();
        responseEntity = responseEntity.replace("<head>","");
        responseEntity = responseEntity.replace("</head>","");
        responseEntity = responseEntity.replace("&","&amp;");//非法字符
        responseEntity = responseEntity.replace(" < ","&lt;");//非法字符
//        responseEntity = responseEntity.replace(" &lt; ","小于");//非法字符
//        responseEntity = responseEntity.replace(">","&gt;");//非法字符
//        responseEntity = responseEntity.replace("\"","&quot;");//非法字符
//        responseEntity = responseEntity.replace("'","&apos;");//非法字符

        try {
            JAXBContext context = JAXBContext.newInstance(Table.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            Table table = (Table)unmarshaller.unmarshal(new StringReader(responseEntity));
            return table.getRoot();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    //发送http请求
    public CloseableHttpResponse accessService(String docType, String requestData) throws IOException {
        ResourceBundle resourceBundle = ResourceBundle.getBundle("rmwebservice");
        String userName = resourceBundle.getString("userName");
        String password = resourceBundle.getString("password");
        String wadl = resourceBundle.getString("wadl");

        //设置身份信息和config
        CredentialsProvider provider = new BasicCredentialsProvider();
        provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));
        CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(provider).build();
        RequestConfig config = RequestConfig.custom().setSocketTimeout(100000000).setConnectTimeout(100000000).build();

        HttpPost httpPost = new HttpPost(wadl);
        httpPost.setHeader("Context-Type","application/xml");
        httpPost.setConfig(config);

        StringBuffer stringBuffer = new StringBuffer("");
        stringBuffer.append("<ns:GET_Input xmlns:ns=\"http://ebsapp.streamax.com/webservices/rest/common_service/INVOKEFMSWS/\"");
        stringBuffer.append(" xmlns:ns1=\"http://xmlns.oracle.com/apps/fnd/soaprovider/plsql/rest/common_service/header\">");
        stringBuffer.append("<ns:InputParameters><ns:P_IFACE_CODE>");
        stringBuffer.append(docType);//报文格式中的 P_IFACE_CODE, 即为请求ERP中接口类型
        stringBuffer.append("</ns:P_IFACE_CODE>");
        stringBuffer.append("<ns:P_BATCH_NUMBER>");
        stringBuffer.append("202103160001");//数据批次编号
        stringBuffer.append("</ns:P_BATCH_NUMBER>");
        stringBuffer.append("<ns:P_REQUEST_DATA>");
        stringBuffer.append(requestData);//插入已转为base64编码格式的请求数据
        stringBuffer.append("</ns:P_REQUEST_DATA>");
        stringBuffer.append("</ns:InputParameters>");
        stringBuffer.append("</ns:GET_Input>");

        StringEntity data = new StringEntity(String.valueOf(stringBuffer), "UTF-8");
        data.setContentType("application/xml");

        httpPost.setEntity(data);
        CloseableHttpResponse response = httpClient.execute(httpPost);

        return response;
    }

    //获取时间, 即为数据批次编号
    public String getDate(){
        LocalDate localDate = LocalDate.now();
        String year = String.valueOf(localDate.getYear());
        String month = String.valueOf(localDate.getMonthValue());
        String day = String.valueOf(localDate.getDayOfMonth());
        String result = year + month + day + "0001";
        return result;
    }

    //获取base64xml编码格式的数据
    public String toBase64Entity(Map<String, String> map) throws UnsupportedEncodingException {
        //遍历map中键值对进xml格式中
        StringBuffer stringBuffer = new StringBuffer("<root><head><H>");
        if ( map != null ){
            Iterator<String> it = map.keySet().iterator();
            while (it.hasNext()){
                String str = it.next();
                if(map.get(str) == null){
                    map.put(str,"");
                }
                if("LINE_NUM".equals(str)){
                    continue;
                }
                if("LOT_NO".equals(str)){
                    continue;
                }
                stringBuffer.append("<");stringBuffer.append(str);stringBuffer.append(">");
                stringBuffer.append(map.get(str));
                stringBuffer.append("</");stringBuffer.append(str);stringBuffer.append(">");
            }
            if(map.get("LINE_NUM")!=null){
                stringBuffer.append("<line><L>");
                stringBuffer.append("<LINE_NUM>"+map.get("LINE_NUM")+"</LINE_NUM>");
                stringBuffer.append("<LOT_NO>"+map.get("LOT_NO")+"</LOT_NO>");
                stringBuffer.append("<QTY>"+map.get("QUANTITY")+"</QTY>");
                stringBuffer.append("</L></line>");
            }

        }
        stringBuffer.append("</H></head></root>");

        //对xml进行base64转码
        String text = String.valueOf(stringBuffer);
        java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
        byte[] textByte = text.getBytes("UTF-8");
        //编码
        String encodedText = encoder.encodeToString(textByte);
        return encodedText;
    }

    public String xmlToPost(String xml) throws UnsupportedEncodingException {

        //对xml进行base64转码
        String text = String.valueOf(xml);
        java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
        byte[] textByte = text.getBytes("UTF-8");
        //编码
        String encodedText = encoder.encodeToString(textByte);
        return encodedText;
    }

    public static String getMessage(String result){
        result = result.replace("&lt;","<");
        result = result.replace("&gt;",">");
        return result;
    }

    public static String stripNonValidXMLCharacters(String in) {
        StringBuffer out = new StringBuffer(); // Used to hold the output.
        char current; // Used to reference the current character.

        if (in == null || ("".equals(in)))
            return ""; // vacancy test.
        for (int i = 0; i < in.length(); i++) {
            current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught
            // here; it should not happen.
            if ((current == 0x9) || (current == 0xA) || (current == 0xD)
                    || ((current >= 0x20) && (current <= 0xD7FF))
                    || ((current >= 0xE000) && (current <= 0xFFFD))
                    || ((current >= 0x10000) && (current <= 0x10FFFF)))
                out.append(current);
        }
        return out.toString();
    }
}
